import { ChangeDetectorRef, Component, Input, OnInit, Output, ViewChild } from '@angular/core';
import { Router } from '@angular/router';
import { AfFormatUtil, AfMessageService } from '@core';
import { STColumn, STComponent } from '@delon/abc/st';
import { ModalHelper, _HttpClient } from '@delon/theme';
import { BehaviorSubject, Observable, of, zip } from 'rxjs';
import { catchError, debounceTime, map, switchMap } from 'rxjs/operators';

import { CodeGenService } from '../../codegen.service';
import { LangDBScriptComponent } from '../../lang/db-script/lang-db-script.component';
import { LangJpaScriptComponent } from '../../lang/jpa-script/lang-jpa-script.component';
import { ConstNamingRule, LangSourceType } from '../../lang/lang';
import { LangService } from '../../lang/lang.service';

@Component({
  selector: 'app-generate-script',
  templateUrl: './generate.script.component.html',
  styleUrls: ['./generate.script.component.less']
})
export class GenerateScriptComponent implements OnInit {
  namingRuleList = ConstNamingRule;

  searchChange$ = new BehaviorSubject('');
  optionList: any[] = [];
  selectedTable: any = undefined;
  target_dbType: any;
  dbSources: any[] | null = null;
  dbSourceName: any = undefined;
  target_dbSources: any[] | null = null;
  target_DbSourceName: any = undefined;

  isLoading = false;
  scriptAll = 'drop table asu_test_all';
  namingRule = 'same';
  btnLoading = false;
  colPrefix: any = '';
  colSuffix: any = '';

  codeMirrorOptions = {
    lineNumbers: true,
    theme: 'idea',
    mode: 'markdown',
    readOnly: true
  };

  dbSourceOptions: any[] | null = [
    {
      value: 'mysql',
      label: 'mysql',
      children: [
        {
          value: 'ms-code-generator',
          label: 'ms-code-generator',
          isLeaf: true
        }
      ]
    },
    {
      value: 'oracle',
      label: 'oracle',
      children: [
        {
          value: 'or-dev-test',
          label: 'or-dev-test',
          isLeaf: true
        }
      ]
    }
  ];

  xTable: any | null = null;
  xColumns: any[] = [];
  @ViewChild('st', { static: false }) st!: STComponent;
  columns: STColumn[] = [
    { title: '序号', index: 'columnId', sort: true },
    { title: '字段英文名', index: 'columnName', sort: true },
    { title: '字段中文名', index: 'columnComment' },
    { title: '数据类型', index: 'dataType', sort: true },
    { title: '长度', index: 'length' },
    { title: '刻度', index: 'scale' },
    { title: '可空', index: 'nullable' },
    { title: '默认值', index: 'dataDefault' }
  ];

  xConstraints: any[] = [];
  @ViewChild('st2', { static: false }) st2!: STComponent;
  constraints: STColumn[] = [
    { title: '序号', index: 'serial', sort: true },
    { title: '表名', index: 'tableName' },
    { title: '约束名称', index: 'constraintName', sort: true },
    { title: '约束类型', index: 'constraintType' },
    {
      title: '约束类型名',
      type: 'tag',
      index: 'constraintType',
      tag: {
        pk: { text: '主键', color: 'success' },
        uin: { text: '惟一索引', color: 'orange' },
        in: { text: '普通', color: 'default' }
      }
    },
    { title: '包含字段', index: 'columnList' },
    { title: '主键自增长', index: 'pkAutoIncrement' }
  ];

  packageName: any = 'com.af.business';
  moduleName: any = 'tmp';
  author: any = '';

  constructor(
    private modal: ModalHelper,
    private http: _HttpClient,
    private msg: AfMessageService,
    private codegen: CodeGenService,
    private cdr: ChangeDetectorRef,
    private router: Router,
    private langServ: LangService
  ) {
    this.author = this.codegen.userName;
  }

  ngOnInit(): void {
    // this.dbSourceOptions = databaseSources;
    this.queryDataSource();
    this.queryDatabaseType();
  }

  public queryDataSource() {
    this.isLoading = true;
    this.cdr.detectChanges();
    try {
      this.langServ.queryDbSourceCascader().subscribe(body => {
        if (body.status) {
          this.dbSourceOptions = body.data;
          // console.log(JSON.stringify(this.dbSourceOptions));
        } else {
          this.msg.notice_warning('查询数据源', `警告编号${body.code};  警告信息${body.msg}`);
        }
      });
    } finally {
      // setTimeout(() => {
      //   this.isLoading = false;
      //   this.cdr.detectChanges();
      // }, 20);
    }
  }

  databaseTypes: any[] = [];

  public queryDatabaseType() {
    this.isLoading = true;
    this.cdr.detectChanges();
    try {
      this.codegen.getDataTypeList().subscribe(body => {
        if (body.status) {
          this.databaseTypes = [];
          this.databaseTypes = body.data;
          // console.log(JSON.stringify(this.databaseTypes));
        } else {
          this.msg.notice_warning('查询数据库类型列表', `警告编号${body.code};  警告信息${body.msg}`);
        }
      });
    } finally {
      setTimeout(() => {
        this.isLoading = false;
        this.cdr.detectChanges();
      }, 200);
    }
  }

  // 通过searchChange，来触发执行查询表列表
  onTableSearch(value: string): void {
    this.isLoading = true;
    this.searchChange$.next(value);
  }

  // 通过选择数据源，来设置searchChange事件
  onCascaderChanges(values: any): void {
    if (values != undefined && values != null) {
      this.dbSourceName = values![1];
      this.target_dbType = values![0];
      this.setOptionListEvent();
      this.selectedTable = '';
    }
  }

  public setOptionListEvent() {
    if (this.dbSourceName == undefined || this.dbSourceName == '') {
      return;
    }

    const getRandomNameList = (name: string): Observable<any> =>
      this.http.get(this.langServ.getTableListUrl(this.dbSourceName, name)).pipe(
        catchError(() => of({ data: [] })),
        map((res: any) => res.data)
      );
    const optionList$: Observable<string[]> = this.searchChange$.asObservable().pipe(debounceTime(500)).pipe(switchMap(getRandomNameList));
    optionList$.subscribe(data => {
      this.optionList = data;
      this.cdr.detectChanges();
      this.isLoading = false;
    });
  }

  // 获取目标数据源
  onCascaderTargetChanges(values: any): void {
    if (values != undefined && values != null) {
      this.target_DbSourceName = values![1];
    }
  }

  public checkParam(): boolean {
    if (this.codegen.isEmpty(this.dbSourceName)) {
      this.msg.notice_warning('警告信息', `请选择数据源`);
      return false;
    }
    if (this.codegen.isEmpty(this.selectedTable)) {
      this.msg.notice_warning('警告信息', `请输入并选择表`);
      return false;
    }
    return true;
  }

  public fetchScript() {
    if (!this.checkParam()) {
      return;
    }

    if (this.codegen.isEmpty(this.target_dbType)) {
      this.msg.notice_warning('警告信息', `请选择脚本数据类型`);
      return;
    }

    this.selectedIndex = 1;

    if (this.target_dbType !== 'flink') {
      this.fetchDDlScript();
    } else if (this.target_dbType === 'flink') {
      this.columnScripts = '';
      this.scriptListAll = '';
      this.fetchFlinkSql();
    }
    this.fetchTableScriptList();
    this.cdr.detectChanges();
  }

  ddlScripts: any[] = [];
  ddlAllScript = '';
  public fetchDDlScript(): void {
    try {
      this.ddlScripts = [];
      this.ddlAllScript = '';

      this.btnLoading = true;
      this.langServ
        .getTableDDLScript(LangSourceType.database, this.dbSourceName, this.selectedTable, this.namingRule, this.target_dbType)
        .subscribe(body => {
          this.ddlAllScript = '';
          if (body.status) {
            this.ddlScripts = body.data;
            // console.log(JSON.stringify(this.ddlScripts));
            this.ddlScripts.forEach(item => {
              this.ddlAllScript = `${this.ddlAllScript + this.codegen.sqlformat(item.script, this.target_dbType)};\n`;
            });
            // console.log(this.ddlAllScript);
          } else {
            this.msg.notice_warning('脚本生产失败', `警告信息: ${body.msg} ; ${body.data}`);
          }
        });
    } finally {
      setTimeout(() => {
        this.btnLoading = false;
        this.cdr.detectChanges();
      }, 1000);
    }
  }

  public fetchFlinkSql(): void {
    if (this.target_DbSourceName === undefined) {
      this.msg.notice_warning('警告信息', `请选择Flink-SQL连接器`);
      return;
    }
    try {
      this.ddlScripts = [];
      this.ddlAllScript = '';

      this.btnLoading = true;
      this.langServ
        .getTableFlinkDDLSql(
          LangSourceType.database,
          this.dbSourceName,
          this.selectedTable,
          this.namingRule,
          this.target_dbType,
          this.target_DbSourceName
        )
        .subscribe(body => {
          this.ddlAllScript = '';
          if (body.status) {
            this.ddlScripts = body.data;
            console.log(JSON.stringify(this.ddlScripts));
            this.ddlScripts.forEach(item => {
              this.ddlAllScript = `${this.ddlAllScript + this.codegen.sqlformat(item.script, this.target_dbType)};\n`;
            });
            console.log(this.ddlAllScript);
          } else {
            this.msg.notice_warning('脚本生产失败', `警告信息: ${body.msg} ; ${body.data}`);
          }
        });
    } finally {
      setTimeout(() => {
        this.btnLoading = false;
        this.cdr.detectChanges();
      }, 1000);
    }
  }

  tableScripts: any[] = [];
  scriptList: any[] = [];
  columnScripts = '';
  scriptListAll = '';
  public fetchTableScriptList(): void {
    this.columnScripts = '';
    this.scriptListAll = '';
    try {
      this.btnLoading = true;
      this.langServ
        .getTableDMLScript(LangSourceType.database, this.dbSourceName, this.selectedTable, this.namingRule, this.target_dbType)
        .subscribe(body => {
          this.columnScripts = '';
          if (body.status) {
            this.tableScripts = body.data;
            console.log(JSON.stringify(this.tableScripts));
            this.tableScripts.forEach(item => {
              this.columnScripts = `${this.columnScripts + this.codegen.sqlformat(item.columnScript)};\n`;
              this.scriptList = item.scriptList;

              this.scriptList.forEach(script => {
                this.scriptListAll = `${this.scriptListAll + script};\n`;
              });
            });
            console.log(this.columnScripts);
            console.log(this.scriptListAll);
          } else {
            this.msg.notice_warning('脚本生产失败', `警告信息: ${body.msg} ; ${body.data}`);
          }
        });
    } finally {
      setTimeout(() => {
        this.btnLoading = false;
        this.cdr.detectChanges();
      }, 1000);
    }
  }

  selectedIndex = 0;
  tableLoading = false;

  public onTableInfo() {
    if (!this.checkParam()) {
      return;
    }

    this.selectedIndex = 0;

    this.xColumns = [];
    this.xConstraints = [];

    this.tableLoading = true;
    this.cdr.detectChanges();
    try {
      this.langServ.getTableInfo(this.dbSourceName, this.selectedTable, this.namingRule).subscribe(body => {
        if (body.status) {
          this.xTable = body.data;
          // console.log(JSON.stringify(this.xTable));
          this.xColumns = body.data.xcolumns;
          // let inConstraint: any[] = this.xTable.inConstraint;
          if (this.xTable.pkConstraint !== undefined) {
            this.xConstraints = [this.xTable.pkConstraint];
          }
          if (this.xTable.uinConstraint !== undefined) {
            this.xConstraints = [...this.xConstraints, this.xTable.uinConstraint];
          }
          if (this.xTable.inConstraint !== undefined) {
            this.xConstraints = [...this.xConstraints, ...this.xTable.inConstraint];
          }
          this.onTongYiCode();
        } else {
          this.msg.notice_warning('查询文件', `无数据`);
        }
      });
    } finally {
      setTimeout(() => {
        this.tableLoading = false;
        this.cdr.detectChanges();
      }, 200);
    }
  }

  jpaEntityScripts: any[] = [];
  javaValue: any = '';
  jpaLoading = false;

  public onJpaCode() {
    if (!this.checkParam()) {
      return;
    }
    this.selectedIndex = 2;

    this.jpaLoading = true;
    this.cdr.detectChanges();
    try {
      this.langServ
        .getJpaCodeList(
          LangSourceType.database,
          this.dbSourceName,
          this.selectedTable,
          this.namingRule,
          this.packageName,
          this.moduleName,
          this.author
        )
        .subscribe(body => {
          if (body.status) {
            const jpaScripts: any[] = body.data;
            if (jpaScripts !== null && jpaScripts.length >= 1) {
              this.jpaEntityScripts = jpaScripts[0].jpaEntityScripts;
            }
            this.jpaEntityScripts.forEach(entity => {
              if (entity.templateType == 'entity') {
                this.javaValue = entity.javaValue;
              }
            });
          } else {
            this.msg.notice_warning('查询文件', `无数据`);
          }
        });
    } finally {
      setTimeout(() => {
        this.jpaLoading = false;
        this.cdr.detectChanges();
      }, 1500);
    }
  }

  downloadJpaZip(record: any = {}) {
    this.cdr.detectChanges();
    try {
      const url = this.langServ.downloadJpaCodeZipUrl(
        LangSourceType.database,
        this.dbSourceName,
        this.selectedTable,
        this.namingRule,
        this.packageName,
        this.moduleName,
        this.author
      );
      window.open(url);
    } finally {
      this.cdr.detectChanges();
    }
  }

  onJpaSelectIndexChange($event: any) {
    this.jpaEntityScripts.forEach(entity => {
      if ($event == 0 && entity.templateType == 'entity') {
        this.javaValue = entity.javaValue;
        return;
      }
      if ($event == 1 && entity.templateType == 'repository') {
        this.javaValue = entity.javaValue;
        return;
      }
      if ($event == 2 && entity.templateType == 'service') {
        this.javaValue = entity.javaValue;
        return;
      }
      if ($event == 3 && entity.templateType == 'controller') {
        this.javaValue = entity.javaValue;
        return;
      }
    });
    this.cdr.detectChanges();
  }

  navigateDbScript(record: any = {}) {
    if (!this.selectedTable) {
      this.msg.msg_warning('请选择一个表');
      return;
    }
    this.router.navigateByUrl(
      `/codegen/lang/db/script?sourceType=${LangSourceType.database}&sourceName=${this.dbSourceName}&sourceLabel=${this.selectedTable}&sourceTable=${this.selectedTable}&namingRule=${this.namingRule}&scriptDbType=${this.target_dbType}`
    );
  }

  navigateJpaScript(record: any = {}) {
    if (!this.selectedTable) {
      this.msg.msg_warning('请选择一个表');
      return;
    }
    this.router.navigateByUrl(
      `/codegen/lang/jpa/script?sourceType=${LangSourceType.database}&sourceName=${this.dbSourceName}&sourceLabel=${this.selectedTable}&sourceTable=${this.selectedTable}&namingRule=${this.namingRule}&scriptDbType=${this.target_dbType}`
    );
  }
  openDbScript() {
    if (!this.selectedTable) {
      this.msg.msg_warning('请选择一个表');
      return;
    }
    const record: any = {
      sourceType: LangSourceType.database,
      sourceName: this.dbSourceName,
      sourceLabel: this.selectedTable,
      sourceTable: this.selectedTable,
      namingRule: this.namingRule,
      scriptDbType: this.target_dbType
    };
    this.modal.create(LangDBScriptComponent, { record }, { size: 'xl' }).subscribe(res => {
      console.log(res);
    });
  }

  openJpaScript() {
    if (!this.selectedTable) {
      this.msg.msg_warning('请选择一个表');
      return;
    }
    const record: any = {
      sourceType: LangSourceType.database,
      sourceName: this.dbSourceName,
      sourceLabel: this.selectedTable,
      sourceTable: this.selectedTable,
      namingRule: this.namingRule,
      scriptDbType: this.target_dbType
    };
    this.modal.create(LangJpaScriptComponent, { record }, { size: 'xl' }).subscribe(res => {
      console.log(res);
    });
  }

  tongYiJson: any = '';
  public onTongYiCode() {
    const tmpColumns: any = [];
    // this.xColumns.forEach(item => {
    //   tmpColumns.push({ col_caption: item.columnComment, col_name: item.columnName });
    // });

    // const tmpJson = {
    //   synonym_infos: '',
    //   schema_infos: [
    //     {
    //       columns: tmpColumns,
    //       table_id: this.xTable.tableName,
    //       table_desc: this.xTable.tableComment
    //     }
    //   ]
    // };
    let colNames = '';
    this.xColumns.forEach(item => {
      if (item.columnComment && item.columnComment.length > 0) {
        colNames = `${colNames},${item.columnComment}`;
      }
      if (item.columnName.includes('yyyymmdd') || item.columnName.includes('_date')) {
        tmpColumns.push({ cn: item.columnComment, en: item.columnName, dataType: 'varchar', example: 'yyyymmdd' });
      } else {
        tmpColumns.push({ cn: item.columnComment, en: item.columnName });
      }
    });
    const tmpJson = {
      colNames: colNames.substring(1),
      columns: tmpColumns,
      table_id: this.xTable.tableName,
      table_name: this.xTable.tableComment,
      table_desc: this.xTable.tableComment
    };
    this.tongYiJson = AfFormatUtil.formatJson(JSON.stringify(tmpJson));
    this.cdr.detectChanges();
  }

  selectedTabIndex = 0;
}
